#include "AReVi/Utils/memoryBlock.h"
using namespace AReVi;

#include "fifo.h"

/******************************************************************************/

AR_CLASS_DEF(FIFO,ArObject)

FIFO::FIFO(ArCW & arCW) : ArObject(arCW), _length(0), _offset(0) {
	_stack = MemoryBlock::NEW();
}

FIFO::~FIFO() {

}

/******************************************************************************/

char * FIFO::access() {
	return _stack->accessMemory() + _offset;
}

bool FIFO::unstack(unsigned int size) {
	// On a besoin d'assez de données
	if (size > getSize()) return false;
	
	_offset += size;
	if (_offset >= _length) {
		// On a atteint le bout de la pile
		_offset = 0;
		_length = 0;
	}
	else if (_offset > getSize()) {
		memcpy((void *) _stack->accessMemory(), (void *) (_stack->accessMemory()+_offset), getSize() * sizeof(char));
		_length -= _offset;
		_offset = 0;
	}

	return true;
}

ArRef<MemoryBlock> FIFO::extractMB(unsigned int size) {
	// On a besoin d'assez de données
	if (size > getSize()) return MemoryBlock::nullRef();
	
	// On créé le block mémoire qui va bien
	ArRef<MemoryBlock> block = MemoryBlock::NEW();
	block->setSize(size); // Pas besoin de tester, renvoi toujours true
	
	// On copie les données dedans
	memcpy((void *) block->accessMemory(), (void *) (_stack->accessMemory()+_offset), size * sizeof(char));
	
	// On dépile les données
	if (! unstack(size)) return MemoryBlock::nullRef();
	else return block;
}

bool FIFO::extract(unsigned int size, char *ptr) {
	// On a besoin d'assez de données
	if (size > getSize()) return false;
	
	// On copie les données dedans
	memcpy((void *) ptr, (void *) (_stack->accessMemory()+_offset), size * sizeof(char));
	
	// On dépile les données
	if (! unstack(size)) return false;
	else return true;
}

bool FIFO::append(unsigned int size, char *ptr) {
	// On a besoin d'assez de place
	if (! _stack->ensureMinSize(_length+size)) return false;
	
	// On ajoute les données
	memcpy((void *) (_stack->accessMemory()+_length), (void *) ptr, size * sizeof(char));

	// On met à jour la taille
	_length += size;
	return true;
}

